﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;
using DataLayer;
using System.Data;

namespace BusinessLayer
{
    public static class BizAdmin
    {
        public static List<IngresoFallido> IngresosFallidos { get; set; }
        public class IngresoFallido
        {
            public string User;
            public int Intentos;

            private IngresoFallido(string stringValue)
            {
                User = stringValue;
                Intentos = 0;// default value
            }

            private IngresoFallido(int intValue)
            {
                User = string.Empty;// default value
                Intentos = intValue;
            }

            public static implicit operator IngresoFallido(Int32 intValue)
            {
                return new IngresoFallido(intValue);
            }
            public static implicit operator IngresoFallido(string stringValue)
            {
                return new IngresoFallido(stringValue);
            }
            public static implicit operator Int32(IngresoFallido instance)
            {
                return instance.Intentos;
            }

            public override string ToString()
            {
                return User;
            }

            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
            public override bool Equals(object obj)
            {
                if (obj is IngresoFallido)
                {
                    return this.User == ((IngresoFallido)obj).User;
                }
                else
                {
                    return false;
                }
            }
        }

        private static int id = 0;
        private static string username;
        private static List<Util.Funcionalidad> functionalitiesAllowed;
        private static bool isFirstLogin = true;
        private static int idAdmin;

        public static bool UserAllowed(string Username, Util.Funcionalidad Func)
        {
            if (id == 0)
            {
                username = Username;
                id = DatAdmin.GetUsuarioId(Username);
                DatAdmin.GetUsuarioAndFuncionalidad(id);
                FillFunctionalities();
            }

            return functionalitiesAllowed.Any(innerFunc => innerFunc == Func);
        }

        private static void FillFunctionalities()
        {
            functionalitiesAllowed = new List<Util.Funcionalidad>();
            functionalitiesAllowed.Add(Util.Funcionalidad.Login);
            foreach (dsBoleto.Funcionalidad_X_RolRow fxrr in Util.DSBoleto.Funcionalidad_X_Rol)
            {
                //Si en Funcionalidad esta la funcionalidad que buscamos
                if (Util.DSBoleto.Funcionalidad.ToList().Any(elem => elem.IdFuncionalidad == fxrr.IdFuncionalidad))
                {
                    //Traeme su descripcion
                    string Description = Util.DSBoleto.Funcionalidad.First
                        (elem => elem.IdFuncionalidad == fxrr.IdFuncionalidad).Descripcion;

                    //Si estan definidos dentro del enum
                    if (Enum.IsDefined(typeof(Util.Funcionalidad), Description))
                    {//Y aun no esta en el List
                        if (!functionalitiesAllowed.Any(innerFunc => innerFunc == Util.StringToEnum<Util.Funcionalidad>(Description)))
                            functionalitiesAllowed.Add(Util.StringToEnum<Util.Funcionalidad>(Description));
                    }
                }
            }
        }

        public static bool LogIn(string Username, string Password)
        {
            id = DatAdmin.GetUsuarioId(Username);

            if (IsFirstLogIn())
            {
                BootstrapFirstLogIn();
            }
            
            
            bool ok = (id = DatAdmin.LogIn(Username, Util.HashPassword(Password))) > 0;
            if (ok)
            {
                username = Username;
                DatAdmin.GetUsuarioAndFuncionalidad(id);
                FillFunctionalities();
            }
            else
            {
                bool Deactivated = false;
                if (IngresosFallidos == null)
                    IngresosFallidos = new List<IngresoFallido>();
                if (IngresosFallidos.Any(Ing => Ing.User == Username))
                    IngresosFallidos.ForEach(Ingreso =>
                    {
                        if (Ingreso.User == Username)
                        {
                            Ingreso.Intentos++;
                            if (Ingreso.Intentos > 2)
                            {
                                Deactivated = true;
                                BizAdmin.DeactivateUser(BizUser.GetUserId(Username));
                            }
                        }
                    });
                else
                    IngresosFallidos.Add(Username);

                if (Deactivated)
                {
                    throw new ApplicationException("Su usuario ha sido bloqueado, comuníquese\n con el admin.");
                }
            }
            if (!ok)
            {
                id = 0;
                username = string.Empty;
                throw new ApplicationException("Usuario invalido o contraseña incorrecta");
            }
            return ok;
        }

        private static void BootstrapFirstLogIn()
        {
            string newPassword = Util.ConfigData["HashedAdminPass"].ToString();
            BizUser.UpdateUser(idAdmin, newPassword);
        }

        public static bool IsFirstLogIn()
        {
            int AdminId;
            isFirstLogin = DatAdmin.IsAdminGralEmpty(out AdminId);
            idAdmin = AdminId;
            return isFirstLogin;
        }

        public static void DeactivateUser(int Id)
        {
            List<Util.DBParameter> MisParams = new List<Util.DBParameter>();
            MisParams.Add(new Util.DBParameter("@Id", Id, DbType.Int32));
            MisParams.Add(new Util.DBParameter("@Active", 0, DbType.Boolean));
            DatUser.UpdateUsuario(MisParams);
        }

        public static bool UserLoggedInAllowed(Util.Funcionalidad Func)
        {
            if (id != 0)
            {
                return functionalitiesAllowed.Any(f => f.Equals(Func));
            }
            else
            {
                if (Func != Util.Funcionalidad.Login)
                {
                    throw new ApplicationException("Usted no esta loggeado. Por favor haga Log in");
                }
                else
                {
                    return true;
                }
            }
        }

        public static void ChangePassword(string p, string p2)
        {
            if (p == p2)
            {
                List<Util.DBParameter> MisParams = new List<Util.DBParameter>();
                MisParams.Add(new Util.DBParameter("@Id", id, DbType.Int32));
                MisParams.Add(new Util.DBParameter("@Pass", Util.HashPassword(p), DbType.String));
                DatUser.UpdateUsuario(MisParams);
            }
            else
                throw new ApplicationException("La contraseña y su confirmación no coinciden");
        }
    }
}
